#include "camera.h"
#include <errno.h>
#include <jpeglib.h>
#include <stdio.h>
#include "capture.h"
#include "welog.h"

unsigned char *JpegToRgba8888(const unsigned char *jpegBuf, unsigned int size, int *width, int *height)
{
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    jpeg_mem_src(&cinfo, jpegBuf, size);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_start_decompress(&cinfo);

    *width = cinfo.output_width;
    *height = cinfo.output_height;
    welog_info("--------width = %d, height = %d, size = %d\n", *width, *height, size);

    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);

    unsigned char *rgba8888_data = (unsigned char*)malloc(cinfo.output_width * cinfo.output_height * 4);

    int y = 0;
    while (cinfo.output_scanline < cinfo.output_height) {
        jpeg_read_scanlines(&cinfo, buffer, 1);
        for (int x = 0; x < cinfo.output_width; x++) {
            int index = (y * cinfo.output_width + x) * 4;
            rgba8888_data[index] = buffer[0][x * cinfo.output_components];
            rgba8888_data[index + 1] = buffer[0][x * cinfo.output_components + 1];
            rgba8888_data[index + 2] = buffer[0][x * cinfo.output_components + 2];
            rgba8888_data[index + 3] = 255;
        }
        y++;
    }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    return rgba8888_data;
}

void RgbaToJpeg(unsigned char* src, int width, int height, const char* comment, size_t *jpegSize, unsigned char **jpegBuf)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    JSAMPROW row_pointer[1];

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;  // RGB
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, 75, TRUE);
    jpeg_mem_dest(&cinfo, jpegBuf, jpegSize);

    jpeg_start_compress(&cinfo, TRUE);

    if (comment) {
        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET*)comment, strlen(comment));
    }

    unsigned char *rgba_data = (unsigned char *)malloc(width * height * 3);
    for (unsigned int i = 0; i < height * width; i++) {
        rgba_data[i * 3 + 0] = src[i * 4 + 0];
        rgba_data[i * 3 + 1] = src[i * 4 + 1];
        rgba_data[i * 3 + 2] = src[i * 4 + 2];
    }

    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &rgba_data[cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    free(rgba_data);
}

static struct DeviceFormat deviceFormat = {
    .fmtDesc.width = 1280,
    .fmtDesc.height = 720,
    .memDesc.memoryType = V4L2_MEMORY_MMAP,
};

void ImageHandle(int index, struct MemoryList *memory)
{
    int width, height;
    size_t jpegSize = 0;
    unsigned char *jpegBuf = NULL;
    welog_info("index = %d, memory = %p", index, memory);
    char srcImage[64] = { 0 };
    char destImage[64] = { 0 };
    snprintf(srcImage, 64, "src_image_%d", index);
    snprintf(destImage, 64, "dest_image_%d", index);
    FILE *fp = fopen(srcImage, "wb+");
    if (fp == NULL) {
        welog_err("fopen file %s failed", srcImage);
        return;
    }
    fwrite(memory->saveImageAddr, memory->length, 1, fp);
    fclose(fp);

    unsigned char *rgbaData = JpegToRgba8888(memory->virtAddr, memory->length, &width, &height);

    RgbaToJpeg(rgbaData, width, height, NULL, &jpegSize, &jpegBuf);

    fp = fopen(destImage, "wb+");
    if (fp == NULL) {
        welog_err("fopen file %s failed", destImage);
        return;
    }
    fwrite(jpegBuf, jpegSize, 1, fp);
    fclose(fp);
    free(jpegBuf);
    free(rgbaData);
}

int main(void) 
{
    int ret = Capture("/dev/usbvideo0", &deviceFormat, ImageHandle);
    if (ret < 0) {
        welog_err("capture failed");
        return -1;
    }
    return 0;
}

